using System.Collections.Generic;
using System.Diagnostics;

namespace Promote {
    public class FixedQueue<T> {
        public FixedQueue(ulong minCapacity) {
            _capacity = ((ulong)1) << (int)Base2.LogCeil(minCapacity);
            _array = new T[_capacity];
            _mask = _capacity - 1;
            _read = _write = 0;
        }

        // Observe
        public bool CanRead()   { return _read != _write; }
        public bool CanWrite()  { return _write != _read + _capacity; }
        public ulong Capacity() { return _capacity; }
        public T Peek() {
            Debug.Assert(CanRead());
            return _array[_read & _mask];
        }
        public bool TryPeek(ref T item) {
            if( CanRead() ) {
                item = _array[_read & _mask];
                return true;
            } else {
                return false;
            }
        }
        public ulong Size()     { return _write - _read; }

        // Modify
        public T Read() {
            Debug.Assert(CanRead());
            return _array[_read++ & _mask];
        }
        public void Write(T item) {
            Debug.Assert(CanWrite());
            _array[_write++ & _mask] = item;
        }
        public bool TryRead(ref T item) {
            if( CanRead() ) {
                item = _array[_read++ & _mask];
                return true;
            } else {
                return false;
            }
        }
        public bool TryWrite(ref T item) {
            if( CanWrite() ) {
                _array[_write++ & _mask] = item;
                return true;
            } else {
                return false;
            }
        }

        private T[] _array;
        private ulong _capacity;
        private ulong _mask;
        private ulong _read;
        private ulong _write;
    }
}

